package com.atguigu.gulimall.seckill.scheduled;

import com.atguigu.gulimall.seckill.service.SeckillService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.SlotCallback;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/*
 * 定时任务
 *  1、@EnableScheduling 开启定时任务
 *  2、@Scheduled 开启一个定时任务
 * 异步任务
 *  1、@EnableAsync 开启异步任务功能
 *  2、@Async 给异步执行的方法加上注解
 *  3、自动配置类 TaskExecutionAutoConfiguration 属性绑定在TaskExecutionProperties
 *      spring.task.execution.pool.core-size=5
 *      spring.task.execution.pool.max-size=50
 */

/**
 * 秒杀商品的定时上架
 */
@Slf4j
@EnableAsync
@EnableScheduling
public class SeckillSkuSchedule {

//    /**
//     * 1、spring中的cron表达式由6位组成，不允许第七位的年
//     * 2、在周几的位置，1-7代表周一到周日：Mon-SUN
//     * 3、定时任务默认是阻塞的，但是不应该阻塞。(解决：使用异步+定时任务来完成定时任务不阻塞的功能)
//     *      1、可以让业务以异步方式运行，自己提交到线程池
//     *      CompletableFuture.runAsync(()->{
//     *             xxxService.hello();
//     *         },executor);
//     *      2、支持定时任务线程池；设置TaskSchedulingProperties; spring.task.scheduling.pool.size=5
//     *      3、让定时任务异步执行
//     */
//    @Async
//    @Scheduled(cron = "*/5 * * ? * *")
//    public void hello() throws InterruptedException {
//        log.info("hello...");
//        Thread.sleep(3000);
//
//    }

    @Autowired
    SeckillService seckillService;
    @Autowired
    RedissonClient redissonClient;

    private final String UPLOAD_LOCK = "seckill:upload:lock";

    //每天3点定时上架，避免重复上架，需要幂等性处理
    @Scheduled(cron = "*/3 * * * * ?")
    public void uploadSeckillSkuLatest3Days(){
        //分布式锁。
        RLock lock = redissonClient.getLock(UPLOAD_LOCK);
        lock.lock(10, TimeUnit.SECONDS);
        try {
            seckillService.uploadSeckillSkuLast3Days();
        }finally {
            lock.unlock();
        }
    }
}
